﻿using System;
using System.Collections.Generic;
using senController.Classes;
using Microsoft.Win32;

namespace senController.classes
{
    class Controller
    {
        //Config
        private int _tickTime = 200; //in Milliseconds
        private int _timePerCar = 800; //in Milliseconds
        private bool _isNight = false;

        private ControllerTimer timer;
        private List<Traffic> _trafficQueue;
        private List<TrafficPlan> _trafficLightQueue;
        private Queue<TrafficPlan> _trafficLightPriorityQueue;
        private Dictionary<String, TrafficPlan> _trafficPlans;
        private Dictionary<String, TrafficLight> _trafficLights;
        private NetworkController _networkController;
        private Settings _settings;

        //record last change
        private int _lastTrafficTime;
        private int _lastLightChangeTime;
        private int _calculatedGreenTime;
        private int _currentTime;
        private int _lastLightState;
        private TrafficPlan _currentPlan;
        private MainWindow _window;

        public Controller(MainWindow window)
        {
            this._lastLightChangeTime = 0; this._calculatedGreenTime = 0; this._currentTime = 0;
            this._window = window;
            this.InitSettings();
        }

        /// <summary>
        /// Timer triggered. 
        /// - Check green light time. IF finished, get new plan from queue
        /// </summary>
        public void TrafficLightControl(int time)
        {
            //Save current time
            this._currentTime = time;
            TimeSpan _timespan = TimeSpan.FromMilliseconds(time);

            //CHECK TIME AND STATE
            if (_timespan.Hours >= 0 && _timespan.Hours < 2) //Check if current hour is between 00.00 and 02.00
            {
                if (!_isNight)
                {
                    _SetTrafficLights(0);
                    _SetCarLight(7);
                    _isNight = true;
                }
            }
            else if (_timespan.Hours >= 2 && _timespan.Hours < 4) // Check if current hour is between 02.00 and 04.00
            {
                _SetTrafficLights(0);
            }
            else if (_lastLightState == 0)
                _SetTrafficLights(3);
            else if (_currentPlan == null) //Check if plan has finished
                _GetNewPlan(time);
            else if ((_lastLightChangeTime + _calculatedGreenTime) <= time) //Check if greentime has passed
                _ProcessCurrentPlanStateChange(time);           
        }

        /// <summary>
        /// Get new plan and send it to simulator
        /// </summary>
        /// <param name="time">current time</param>
        private void _GetNewPlan(int time)
        {

            //Write queue information on command promt
            String temp = "";
            temp = "Queue: ";
            foreach (TrafficPlan plan in this._trafficLightQueue)
                temp += plan.GetName() + ", ";
            Console.WriteLine();
            Console.WriteLine(temp);

            temp = "PriorityQueue: ";
            foreach (TrafficPlan plan in this._trafficLightPriorityQueue)
                temp += plan.GetName() + ", ";
            Console.WriteLine(temp);
            Console.WriteLine();
            //End write queue informtion on command promt

            //Check if plans have to be moved to priority queue
            List<TrafficPlan> priorityplan = new List<TrafficPlan>();
            foreach (TrafficPlan plan in _trafficLightQueue)
            {
                if (plan.MoveToPriority(time))
                {
                    //Remove plan from normal to priority queue
                    priorityplan.Add(plan);                    
                }
            }
            foreach (TrafficPlan removePlan in priorityplan)
            {
                _trafficLightQueue.Remove(removePlan);
                _trafficLightPriorityQueue.Enqueue(removePlan);
            }

            //Get new plan
            //From priority queue
            if (_trafficLightPriorityQueue.Count > 0)
                _currentPlan = _trafficLightPriorityQueue.Dequeue();
            //From normal queue
            else if (_trafficLightQueue.Count > 0)
            {
                _currentPlan = _trafficLightQueue[0];
                _trafficLightQueue.RemoveAt(0);
            }
            //Both empty: start first plan
            else
                _currentPlan = _trafficPlans["0"];
            //Calculate new greentime.
            _calculatedGreenTime = _currentPlan.GetGreenTime(_timePerCar, Convert.ToInt16(_settings.minGreenTime), Convert.ToInt16(_settings.maxGreenTime));
            this._lastLightChangeTime = time;
            //Set trafficlights to green.
            _ProcessTrafficLights(_currentPlan, 1);
        }

        /// <summary>
        /// Change current plan to new state.
        /// </summary>
        /// <param name="time">current time</param>
        private void _ProcessCurrentPlanStateChange(int time)
        {
            //Check current state
            if (_currentPlan.getState() == 1)
            {
                //Light is green, set Orange. add orangetime
                _ProcessTrafficLights(_currentPlan, 2);
                _calculatedGreenTime += Convert.ToInt16(_settings.orangeTime);
            }
            else
            {
                //Set stop state and set last changed time
                //Remove plan
                _ProcessTrafficLights(_currentPlan, 3);
                this._lastLightChangeTime = time;
                this._currentPlan.ClearInQueue();
                //Check if cars are still in lane.
                if (this._currentPlan.CheckCarsInLanes())
                {
                    if (this._currentPlan.IsPriority() && !this._trafficLightPriorityQueue.Contains(this._currentPlan))
                        this._trafficLightPriorityQueue.Enqueue(this._currentPlan);
                    else if (!this._trafficLightQueue.Contains(this._currentPlan))
                        this._trafficLightQueue.Add(this._currentPlan);
                }                    
                this._currentPlan = null;
            }           
        }

        /// <summary>
        /// Timer triggered. 
        /// Check for traffic to be sent to simulator
        /// </summary>
        /// <param name="time">current timestamp</param>
        public void TrafficControl(int timePassedSinceLastCall)
        {
            //Check if new traffic can be sent to simulator
            if (_trafficQueue.Count > 0)
            {
                //Get local copy of traffic
                Traffic traffic = _trafficQueue[0];
                //Check if spawntime equals the time since last 'traffic release'
                int spawntime = traffic.getSpawntime();
                if (_lastTrafficTime >= spawntime)
                {
                    //send traffic to network
                    _networkController.SetTraffic(traffic.getType(), traffic.getLocation(), traffic.getDirection());
                    _trafficQueue.RemoveAt(0);
                    //reset last release time
                    //lastTrafficTime = 0;
                }
                else
                    //add second to releasetime
                    _lastTrafficTime += timePassedSinceLastCall;
            }
            else
                Console.WriteLine("Traffic queue is empty.");
            
        }

        /// <summary>
        /// Send trafficlight information to network controller
        /// </summary>
        /// <param name="plan">The plan which has to change</param>
        /// <param name="newState">new state for trafficlights</param>
        private void _ProcessTrafficLights(TrafficPlan plan, int newState)
        {
            _lastLightState = newState;
            foreach (TrafficLight light in plan.GetTrafficLights())
            {          
                int state = newState;
                //Green state?
                if (state == 1)
                    if (light.GetName().Contains("6")) //Is Bus?
                    {
                        state = plan.GetBusState(); //Set busstate instead of greenstate
                    }
                _networkController.SetTrafficLight(light.GetName(), state);
            }
            plan.setState(newState);    
        }

        /// <summary>
        /// Set all trafficlights in one state
        /// </summary>
        /// <param name="state">new state</param>
        private void _SetTrafficLights(int state)
        {
            //Check if last state is the same as last state
            if (_lastLightState == -1 || _lastLightState != state)
            {
                // Loop over pairs with foreach
                foreach (KeyValuePair<string, TrafficLight> light in _trafficLights)
                {
                    TrafficLight trafficLight = light.Value;
                    _networkController.SetTrafficLight(trafficLight.GetName(), state);
                }
                //change last state
                _lastLightState = state;
            }
        }

        private void _SetCarLight(int state)
        {
            if (_lastLightState == -1 || _lastLightState != state)
            {
                //north
                _networkController.SetTrafficLight("N3", state);
                _networkController.SetTrafficLight("N4", state);
                _networkController.SetTrafficLight("N5", state);
                //east
                _networkController.SetTrafficLight("E3", state);
                _networkController.SetTrafficLight("E4", state);
                _networkController.SetTrafficLight("E5", state);
                //south
                _networkController.SetTrafficLight("S3", state);
                _networkController.SetTrafficLight("S4", state);
                _networkController.SetTrafficLight("S5", state);
                //west
                _networkController.SetTrafficLight("W3", state);
                _networkController.SetTrafficLight("W4", state);
                _networkController.SetTrafficLight("W5", state);
            }
            //change last state
            _lastLightState = state;
        }

        /// <summary>
        /// Retreive info from networkcontroller about triggered sensor.
        /// Put sensor trafficlightplan into queue.
        /// </summary>
        public void ProcessSensorInformation(string trafficLightID, int distance, string direction = "")
        {
            //BUS
            if (trafficLightID.Contains("6"))
            {
                if (distance == 100)
                {
                    //Check if one of the plans of trafficlight are already in queue.
                    bool alreadyInQueue = false;
                    foreach (TrafficPlan plan in _trafficLights[trafficLightID].GetTrafficPlans())
                        if ((_trafficLightQueue.Contains(plan) || _trafficLightPriorityQueue.Contains(plan) || plan == _currentPlan) && plan.GetBusDirection(trafficLightID.Substring(0, 1)) == direction)
                            alreadyInQueue = true;
                    //Put plan in queue if it isn't already
                    if (!alreadyInQueue)
                    {
                        //get first plan from trafficlight and add it to queue
                        TrafficPlan currentPlan = _trafficLights[trafficLightID].GetTrafficPlan(0);
                        foreach (TrafficPlan plan in _trafficLights[trafficLightID].GetTrafficPlans())
                            if (plan.GetBusDirection(trafficLightID.Substring(0, 1)) == direction)
                            {
                                currentPlan = plan;
                                break;
                            }
                        currentPlan.SetTimeInQueue(_currentTime);
                        _trafficLightPriorityQueue.Enqueue(currentPlan);
                    }
                    //Add an vehicle to trafficlight-queue (in consideration the direction)
                    _trafficLights[trafficLightID].AddCarToQueue(GetBusState(trafficLightID.Substring(0, 1), direction));
                }
                else if (distance == 1)
                {
                    //Bus drove away, remove one car from queue (in consideration the direction)
                    _trafficLights[trafficLightID].RemoveCarFromQueue(GetBusState(trafficLightID.Substring(0,1), direction));
                }
            }
            //OTHER TRAFFIC
            else if (!trafficLightID.Contains("8"))
            {
                //First Sensor
                if (distance == 100)
                {
                    //Check if one of the plans of trafficlight are already in queue.
                    bool alreadyInQueue = false;
                    foreach (TrafficPlan plan in _trafficLights[trafficLightID].GetTrafficPlans())
                        if (_trafficLightQueue.Contains(plan) || _trafficLightPriorityQueue.Contains(plan) || plan == _currentPlan)
                            alreadyInQueue = true;
                    //Put plan in queue if it isn't already
                    if (!alreadyInQueue)
                    {
                        //get first plan from trafficlight and add it to queue
                        TrafficPlan currentPlan = _trafficLights[trafficLightID].GetTrafficPlan(0);
                        currentPlan.SetTimeInQueue(_currentTime);
                        _trafficLightQueue.Add(currentPlan);
                    }
                    //Add an vehicle to trafficlight-queue
                    _trafficLights[trafficLightID].AddCarToQueue();
                }
                //Second sensor
                else if (distance == 1)
                {
                    //Vehicle drove away, remove one car from queue
                    _trafficLights[trafficLightID].RemoveCarFromQueue();
                }
            }
        }

        /// <summary>
        /// Get statenumber from location and direction
        /// </summary>
        /// <param name="currentLocation">current location of bus</param>
        /// <param name="direction">direction the bus wants to go</param>
        /// <returns>busstate (4,5,6)</returns>
        public int GetBusState(string currentLocation, string direction)
        {
            //Translate location (NESW) to number
            int currentPole = getPoleNumber(currentLocation);
            int directionPole = getPoleNumber(direction);

            int number = directionPole - currentPole;
            int busState = 6;
            if (number == -1 || number == 3)
                busState = 5;
            else if (number == 1 || number == -3)
                busState = 4;
            else if (number == -2 || number == 2)
                busState = 6;         
           
            return busState;
        }

        /// <summary>
        /// Helper function for GetBusState
        /// Return pole number (1-4) FROM pole (N-E-S-W)
        /// </summary>
        /// <param name="currentLocation">location NESW</param>
        /// <returns>Pole number 1234</returns>
        private int getPoleNumber(string currentLocation)
        {
            switch (currentLocation)
            {
                case "N":
                    return 1;
                case "E":
                    return 2;
                case "Z":
                    return 3;
                case "W":
                    return 4;
                default:
                    return 0;
            }
        }

        #region initialisation

        /// <summary>
        /// Initialize all settings
        /// </summary>
        private void InitSettings()
        {     
            //initialise trafficplans and lights
            this.InitialiseTrafficLights();
            this.InitialiseTrafficPlans();

            //initialise network
            _networkController = new NetworkController(4321, "141.252.217.166", this);
            //_networkController = new NetworkController(4321, "127.0.0.1", this);

            //Initialise queues
            _trafficLightQueue = new List<TrafficPlan>();
            _trafficLightPriorityQueue = new Queue<TrafficPlan>();

        }

        /// <summary>
        /// Initialize all traffic lights and put them into dictionary with light-code
        /// </summary>
        private void InitialiseTrafficLights()
        {
            //Generate trafficlight names
            String[] trafficLightArray = {  "N1", "N2", "N3", "N4", "N5", "N6", "N7", "N8", 
                                            "E1", "E2", "E3", "E4", "E5", "E6", "E7", "E8",
                                            "S1", "S2", "S3", "S4", "S5", "S6", "S7", "S8",
                                            "W1", "W2", "W3", "W4", "W5", "W6", "W7", "W8" };
            //Initialise trafficlights dictionary
            this._trafficLights = new Dictionary<string, TrafficLight>(trafficLightArray.Length);
            //Add trafficlights to dictionary
            foreach (String light in trafficLightArray)
                this._trafficLights.Add(light, new TrafficLight(light));
        }

        /// <summary>
        /// Create traffic plans and add traffic lights to it.
        /// </summary>
        private void InitialiseTrafficPlans()
        {
            this._trafficPlans = new Dictionary<string, TrafficPlan>();
            //Trafficplan 0: AUTO Rechtdoor + rechtsaf NZ
            this._trafficPlans.Add("0", new TrafficPlan(this, "0"));
            this._trafficPlans["0"].AddTrafficLight(_trafficLights["N4"]);
            this._trafficPlans["0"].AddTrafficLight(_trafficLights["N5"]);
            this._trafficPlans["0"].AddTrafficLight(_trafficLights["S4"]);
            this._trafficPlans["0"].AddTrafficLight(_trafficLights["S5"]);
            this._trafficPlans["0"].AddTrafficLight(_trafficLights["N8"]);
            this._trafficPlans["0"].AddTrafficLight(_trafficLights["E8"]);
            this._trafficPlans["0"].AddTrafficLight(_trafficLights["S8"]);
            this._trafficPlans["0"].AddTrafficLight(_trafficLights["W8"]);

            //Trafficplan 1: AUTO Rechtdoor + rechtsaf EW
            this._trafficPlans.Add("1", new TrafficPlan(this, "1"));
            this._trafficPlans["1"].AddTrafficLight(_trafficLights["E4"]);
            this._trafficPlans["1"].AddTrafficLight(_trafficLights["E5"]);
            this._trafficPlans["1"].AddTrafficLight(_trafficLights["W4"]);
            this._trafficPlans["1"].AddTrafficLight(_trafficLights["W5"]);
            this._trafficPlans["1"].AddTrafficLight(_trafficLights["N8"]);
            this._trafficPlans["1"].AddTrafficLight(_trafficLights["E8"]);
            this._trafficPlans["1"].AddTrafficLight(_trafficLights["S8"]);
            this._trafficPlans["1"].AddTrafficLight(_trafficLights["W8"]);

            //Trafficplan 2: AUTO Linksaf NZ, rechtsaf EW
            this._trafficPlans.Add("2", new TrafficPlan(this, "2"));
            this._trafficPlans["2"].AddTrafficLight(_trafficLights["N3"]);
            this._trafficPlans["2"].AddTrafficLight(_trafficLights["S3"]);
            this._trafficPlans["2"].AddTrafficLight(_trafficLights["W5"]);
            this._trafficPlans["2"].AddTrafficLight(_trafficLights["E5"]);
            this._trafficPlans["2"].AddTrafficLight(_trafficLights["N8"]);
            this._trafficPlans["2"].AddTrafficLight(_trafficLights["E8"]);
            this._trafficPlans["2"].AddTrafficLight(_trafficLights["S8"]);
            this._trafficPlans["2"].AddTrafficLight(_trafficLights["W8"]);

            //Trafficplan 3: AUTO Linksaf EW, rechtsaf NZ
            this._trafficPlans.Add("3", new TrafficPlan(this, "3"));
            this._trafficPlans["3"].AddTrafficLight(_trafficLights["N5"]);
            this._trafficPlans["3"].AddTrafficLight(_trafficLights["S5"]);
            this._trafficPlans["3"].AddTrafficLight(_trafficLights["W3"]);
            this._trafficPlans["3"].AddTrafficLight(_trafficLights["E3"]);
            this._trafficPlans["3"].AddTrafficLight(_trafficLights["N8"]);
            this._trafficPlans["3"].AddTrafficLight(_trafficLights["E8"]);
            this._trafficPlans["3"].AddTrafficLight(_trafficLights["S8"]);
            this._trafficPlans["3"].AddTrafficLight(_trafficLights["W8"]);
            
            //Trafficplan 4.1: BUS Rechtdoor NZ, AUTO linksaf NE
            this._trafficPlans.Add("4.1", new TrafficPlan(this, "4.1", true));
            this._trafficPlans["4.1"].SetBusState(6);
            //bus
            this._trafficPlans["4.1"].AddTrafficLight(_trafficLights["N6"]);
            //auto
            this._trafficPlans["4.1"].AddTrafficLight(_trafficLights["N3"]);
            //fietsers
            this._trafficPlans["4.1"].AddTrafficLight(_trafficLights["N8"]);
            this._trafficPlans["4.1"].AddTrafficLight(_trafficLights["E8"]);
            this._trafficPlans["4.1"].AddTrafficLight(_trafficLights["S8"]);
            this._trafficPlans["4.1"].AddTrafficLight(_trafficLights["W8"]);

            //Trafficplan 4.2: BUS Rechtdoor ZN, AUTO linksaf SW
            this._trafficPlans.Add("4.2", new TrafficPlan(this, "4.2", true));
            this._trafficPlans["4.2"].SetBusState(6);
            //bus
            this._trafficPlans["4.2"].AddTrafficLight(_trafficLights["S6"]);
            //auto
            this._trafficPlans["4.2"].AddTrafficLight(_trafficLights["S3"]);
            //fietsers
            this._trafficPlans["4.2"].AddTrafficLight(_trafficLights["N8"]);
            this._trafficPlans["4.2"].AddTrafficLight(_trafficLights["E8"]);
            this._trafficPlans["4.2"].AddTrafficLight(_trafficLights["S8"]);
            this._trafficPlans["4.2"].AddTrafficLight(_trafficLights["W8"]);

            //Trafficplan 4.3: BUS Rechtdoor NZ en ZN
            this._trafficPlans.Add("4.3", new TrafficPlan(this, "4.3", true));
            this._trafficPlans["4.3"].SetBusState(6);
            this._trafficPlans["4.3"].AddTrafficLight(_trafficLights["N6"]);
            this._trafficPlans["4.3"].AddTrafficLight(_trafficLights["S6"]);
            this._trafficPlans["4.3"].AddTrafficLight(_trafficLights["N8"]);
            this._trafficPlans["4.3"].AddTrafficLight(_trafficLights["E8"]);
            this._trafficPlans["4.3"].AddTrafficLight(_trafficLights["S8"]);
            this._trafficPlans["4.3"].AddTrafficLight(_trafficLights["W8"]);

            //Trafficplan 5.1: BUS Rechtdoor EW, AUTO linksaf EW
            this._trafficPlans.Add("5.1", new TrafficPlan(this, "5.1", true));
            this._trafficPlans["5.1"].SetBusState(6);
            this._trafficPlans["5.1"].AddTrafficLight(_trafficLights["E6"]);
            this._trafficPlans["5.1"].AddTrafficLight(_trafficLights["E3"]);
            this._trafficPlans["5.1"].AddTrafficLight(_trafficLights["N8"]);
            this._trafficPlans["5.1"].AddTrafficLight(_trafficLights["E8"]);
            this._trafficPlans["5.1"].AddTrafficLight(_trafficLights["S8"]);
            this._trafficPlans["5.1"].AddTrafficLight(_trafficLights["W8"]);

            //Trafficplan 5.2: BUS Rechtdoor WE, AUTO linksaf WN
            this._trafficPlans.Add("5.2", new TrafficPlan(this, "5.2", true));
            this._trafficPlans["5.2"].SetBusState(6);
            this._trafficPlans["5.2"].AddTrafficLight(_trafficLights["W6"]);
            this._trafficPlans["5.2"].AddTrafficLight(_trafficLights["W3"]);
            this._trafficPlans["5.2"].AddTrafficLight(_trafficLights["N8"]);
            this._trafficPlans["5.2"].AddTrafficLight(_trafficLights["E8"]);
            this._trafficPlans["5.2"].AddTrafficLight(_trafficLights["S8"]);
            this._trafficPlans["5.2"].AddTrafficLight(_trafficLights["W8"]);

            //Trafficplan 5.3: BUS Rechtdoor EW en WE
            this._trafficPlans.Add("5.3", new TrafficPlan(this, "5.3", true));
            this._trafficPlans["5.3"].SetBusState(6);
            this._trafficPlans["5.3"].AddTrafficLight(_trafficLights["E6"]);
            this._trafficPlans["5.3"].AddTrafficLight(_trafficLights["W6"]);
            this._trafficPlans["5.3"].AddTrafficLight(_trafficLights["N8"]);
            this._trafficPlans["5.3"].AddTrafficLight(_trafficLights["E8"]);
            this._trafficPlans["5.3"].AddTrafficLight(_trafficLights["S8"]);
            this._trafficPlans["5.3"].AddTrafficLight(_trafficLights["W8"]);

            //Trafficplan 6: BUS Rechtsaf NZ, Auto Rechtdoor
            this._trafficPlans.Add("6", new TrafficPlan(this, "6", true));
            this._trafficPlans["6"].SetBusState(5);
            this._trafficPlans["6"].AddTrafficLight(_trafficLights["N6"]);
            this._trafficPlans["6"].AddTrafficLight(_trafficLights["S6"]);
            this._trafficPlans["6"].AddTrafficLight(_trafficLights["N4"]);
            this._trafficPlans["6"].AddTrafficLight(_trafficLights["S4"]);
            this._trafficPlans["6"].AddTrafficLight(_trafficLights["N8"]);
            this._trafficPlans["6"].AddTrafficLight(_trafficLights["E8"]);
            this._trafficPlans["6"].AddTrafficLight(_trafficLights["S8"]);
            this._trafficPlans["6"].AddTrafficLight(_trafficLights["W8"]);

            //Trafficplan 7: BUS Rechtsaf EW, auto rechtdoor
            this._trafficPlans.Add("7", new TrafficPlan(this, "7", true));
            this._trafficPlans["7"].SetBusState(5);
            this._trafficPlans["7"].AddTrafficLight(_trafficLights["E4"]);
            this._trafficPlans["7"].AddTrafficLight(_trafficLights["E6"]);
            this._trafficPlans["7"].AddTrafficLight(_trafficLights["W4"]);
            this._trafficPlans["7"].AddTrafficLight(_trafficLights["W6"]);
            this._trafficPlans["7"].AddTrafficLight(_trafficLights["N8"]);
            this._trafficPlans["7"].AddTrafficLight(_trafficLights["E8"]);
            this._trafficPlans["7"].AddTrafficLight(_trafficLights["S8"]);
            this._trafficPlans["7"].AddTrafficLight(_trafficLights["W8"]);
            
            //Trafficplan 12: BUS Linksaf NZ, rechtsaf EW
            this._trafficPlans.Add("12", new TrafficPlan(this, "12", true));
            this._trafficPlans["12"].SetBusState(4);
            this._trafficPlans["12"].AddTrafficLight(_trafficLights["N6"]);
            this._trafficPlans["12"].AddTrafficLight(_trafficLights["S6"]);
            this._trafficPlans["12"].AddTrafficLight(_trafficLights["W5"]);
            this._trafficPlans["12"].AddTrafficLight(_trafficLights["E5"]);
            this._trafficPlans["12"].AddTrafficLight(_trafficLights["N8"]);
            this._trafficPlans["12"].AddTrafficLight(_trafficLights["E8"]);
            this._trafficPlans["12"].AddTrafficLight(_trafficLights["S8"]);
            this._trafficPlans["12"].AddTrafficLight(_trafficLights["W8"]);

            //Trafficplan 13: BUS Rechtsaf EW, linksaf NZ
            this._trafficPlans.Add("13", new TrafficPlan(this, "13", true));
            this._trafficPlans["13"].SetBusState(4);
            this._trafficPlans["13"].AddTrafficLight(_trafficLights["N5"]);
            this._trafficPlans["13"].AddTrafficLight(_trafficLights["S5"]);
            this._trafficPlans["13"].AddTrafficLight(_trafficLights["W6"]);
            this._trafficPlans["13"].AddTrafficLight(_trafficLights["E6"]);
            this._trafficPlans["13"].AddTrafficLight(_trafficLights["N8"]);
            this._trafficPlans["13"].AddTrafficLight(_trafficLights["E8"]);
            this._trafficPlans["13"].AddTrafficLight(_trafficLights["S8"]);
            this._trafficPlans["13"].AddTrafficLight(_trafficLights["W8"]);

            //Trafficplan 8: Fietsers
            this._trafficPlans.Add("8", new TrafficPlan(this, "8", false, 3000000));
            this._trafficPlans["8"].AddTrafficLight(_trafficLights["N7"]);
            this._trafficPlans["8"].AddTrafficLight(_trafficLights["N8"]);
            this._trafficPlans["8"].AddTrafficLight(_trafficLights["S7"]);
            this._trafficPlans["8"].AddTrafficLight(_trafficLights["S8"]);
            this._trafficPlans["8"].AddTrafficLight(_trafficLights["E7"]);
            this._trafficPlans["8"].AddTrafficLight(_trafficLights["E8"]);
            this._trafficPlans["8"].AddTrafficLight(_trafficLights["W7"]);
            this._trafficPlans["8"].AddTrafficLight(_trafficLights["W8"]);

            //Trafficplan 9: Voetgangers
            this._trafficPlans.Add("9", new TrafficPlan(this, "9", false, 3000000));
            this._trafficPlans["9"].AddTrafficLight(_trafficLights["N1"]);
            this._trafficPlans["9"].AddTrafficLight(_trafficLights["N2"]);
            this._trafficPlans["9"].AddTrafficLight(_trafficLights["E1"]);
            this._trafficPlans["9"].AddTrafficLight(_trafficLights["E2"]);
            this._trafficPlans["9"].AddTrafficLight(_trafficLights["S1"]);
            this._trafficPlans["9"].AddTrafficLight(_trafficLights["S2"]);
            this._trafficPlans["9"].AddTrafficLight(_trafficLights["W1"]);
            this._trafficPlans["9"].AddTrafficLight(_trafficLights["W2"]);

            //Trafficplan 10: Voetgangers + NW autos
            this._trafficPlans.Add("10", new TrafficPlan(this, "10", false, 3000000));
            this._trafficPlans["10"].AddTrafficLight(_trafficLights["N4"]);
            this._trafficPlans["10"].AddTrafficLight(_trafficLights["E1"]);
            this._trafficPlans["10"].AddTrafficLight(_trafficLights["E2"]);
            this._trafficPlans["10"].AddTrafficLight(_trafficLights["S4"]);
            this._trafficPlans["10"].AddTrafficLight(_trafficLights["W1"]);
            this._trafficPlans["10"].AddTrafficLight(_trafficLights["W2"]);

            //Trafficplan 11: Voetgangers + EW autos
            this._trafficPlans.Add("11", new TrafficPlan(this, "11", false, 3000000));
            this._trafficPlans["11"].AddTrafficLight(_trafficLights["E4"]);
            this._trafficPlans["11"].AddTrafficLight(_trafficLights["N1"]);
            this._trafficPlans["11"].AddTrafficLight(_trafficLights["N2"]);
            this._trafficPlans["11"].AddTrafficLight(_trafficLights["W4"]);
            this._trafficPlans["11"].AddTrafficLight(_trafficLights["S1"]);
            this._trafficPlans["11"].AddTrafficLight(_trafficLights["S2"]);
        }

        #endregion

        #region GUI

        /// <summary>
        /// Start the server.
        /// Note it can take a long time, because the method waits for a client.
        /// </summary>
        public void StartServer()
        {
            _networkController.InitializeNetwork();
            
        }

        public void StartStart()
        {
            this._SetTrafficLights(3);
            timer.run();
        }

        /// <summary>
        /// Places the message in a textbox on the window
        /// </summary>
        /// <param name="message">message to display</param>
        public void Message(String message)
        {
            _window.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Send,
                new Action(
                    delegate()
                    {
                        _window.tBoxMessages.AppendText(message + "\n");
                    }
            ));
        }

        /// <summary>
        /// Set the timer
        /// </summary>
        /// <param name="time">Date in string format</param>
        public void TimeUpdate(string time)
        {
            _window.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Send,
                new Action(
                    delegate()
                    {
                        _window.lblTime.Content = time;
                    }
            ));
        }

        /// <summary>
        /// Open's a filedialog and let's the user choose a XML file
        /// It also applies the settings in the XML.
        /// </summary>
        public void loadXML()
        {
            OpenFileDialog fileDialog = new OpenFileDialog();
            fileDialog.Filter = "XML|*.xml";
            fileDialog.Title = "Select an XML file";
            fileDialog.Multiselect = false;

            // Show the Dialog.
            // If the user clicked OK in the dialog and
            // a .XML file was selected, open it.            
            if (fileDialog.ShowDialog() == true)
            {
                XmlReader reader = new XmlReader(fileDialog.FileName);
                _trafficQueue = reader.readTraffic();
                _settings = reader.readSettings();
                _window.btnStartServer.IsEnabled = true;

                //initialise timer
                this.timer = new ControllerTimer(this, _tickTime,(int)TimeSpan.Parse(_settings.startDate).TotalMilliseconds);
                _window.lblTime.Content = _settings.startDate;
            }
        }

        /// <summary>
        /// Enables the button start
        /// </summary>
        public void btnStartIsEnabled()
        {
            _window.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Send,
               new Action(
                   delegate()
                   {
                       _window.btnRun.IsEnabled = true;
                   }
           ));
        }

        public void btnStop()
        {
            this.timer.stop();
        }

        /// <summary>
        /// Switch network mode between readint and readbyte
        /// </summary>
        public void btnSwitch()
        {
            _networkController.SwitchMode();
        }

        public void btnSwitchDisabled()
        {
            _window.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Send,
               new Action(
                   delegate()
                   {
                       _window.btnSwitch.IsEnabled = false;
                   }
           ));
        }

        #endregion
    }
}